3ddb79c2YTaZwOqWin9-QNgHge5RVw xen/include/hypervisor-ifs/block.h
3ddb79c25UE59iu4JJcbRalx95mvcg xen/include/hypervisor-ifs/hypervisor-if.h
3ddb79c2oRPrzClk3zbTkRHlpumzKA xen/include/hypervisor-ifs/network.h
+3e676eb5yHx7feWgYoqlwD2Z9WsY1w xen/include/hypervisor-ifs/xeno-major.h
3ddb79c4qbCoOFHrv9sCGshbWzBVlQ xen/include/scsi/scsi.h
3ddb79c4R4iVwqIIeychVQYmIH4FUg xen/include/scsi/scsi_ioctl.h
3ddb79c4yw_mfd4Uikn3v_IOPRpa1Q xen/include/scsi/scsicam.h
3e5a4e65iHEuC5sjFhj42XALYbLVRw xenolinux-2.4.21-pre4-sparse/arch/xeno/drivers/block/Makefile
3e5a4e65pP5spJErBW69pJxSSdK9RA xenolinux-2.4.21-pre4-sparse/arch/xeno/drivers/block/xl_block.c
3e5a4e65GtI9JZRAjuRdXaxt_4ohyQ xenolinux-2.4.21-pre4-sparse/arch/xeno/drivers/block/xl_block_test.c
-3e5d129aDldt6geU2-2SzBae34sQzg xenolinux-2.4.21-pre4-sparse/arch/xeno/drivers/block/xl_segment.c
+3e676eb5RXnHzSHgA1BvM0B1aIm4qg xenolinux-2.4.21-pre4-sparse/arch/xeno/drivers/block/xl_segment.c
+3e5d129aDldt6geU2-2SzBae34sQzg xenolinux-2.4.21-pre4-sparse/arch/xeno/drivers/block/xl_segment_proc.c
3e5a4e65G3e2s0ghPMgiJ-gBTUJ0uQ xenolinux-2.4.21-pre4-sparse/arch/xeno/drivers/console/Makefile
3e5a4e651TH-SXHoufurnWjgl5bfOA xenolinux-2.4.21-pre4-sparse/arch/xeno/drivers/console/console.c
3e5a4e656nfFISThfbyXQOA6HN6YHw xenolinux-2.4.21-pre4-sparse/arch/xeno/drivers/dom0/Makefile
static void io_schedule(unsigned long unused);
static int do_block_io_op_domain(struct task_struct *p, int max_to_do);
static void dispatch_rw_block_io(struct task_struct *p, int index);
-static void dispatch_probe_block_io(struct task_struct *p, int index);
+static void dispatch_probe_blk(struct task_struct *p, int index);
+static void dispatch_probe_seg(struct task_struct *p, int index);
static void dispatch_debug_block_io(struct task_struct *p, int index);
static void dispatch_create_segment(struct task_struct *p, int index);
static void dispatch_delete_segment(struct task_struct *p, int index);
dispatch_rw_block_io(p, i);
break;
- case XEN_BLOCK_PROBE:
- dispatch_probe_block_io(p, i);
+ case XEN_BLOCK_PROBE_BLK:
+ dispatch_probe_blk(p, i);
+ break;
+
+ case XEN_BLOCK_PROBE_SEG:
+ dispatch_probe_seg(p, i);
break;
case XEN_BLOCK_DEBUG:
xvd = phys_to_virt((unsigned long)blk_ring->ring[index].req.buffer);
result = xen_segment_create(xvd);
+
make_response(p, blk_ring->ring[index].req.id,
XEN_BLOCK_SEG_CREATE, result);
return;
DPRINTK("dispatch_delete_segment: unimplemented\n");
}
-static void dispatch_probe_block_io(struct task_struct *p, int index)
+static void dispatch_probe_blk(struct task_struct *p, int index)
{
extern void ide_probe_devices(xen_disk_info_t *xdi, int *count,
drive_t xdrives[]);
ide_probe_devices(xdi, &num_xdrives, xdrives);
/* scsi_probe_devices(xdi, &num_xdrives, xdrives); */ /* future */
- make_response(p, blk_ring->ring[index].req.id, XEN_BLOCK_PROBE, 0);
+ make_response(p, blk_ring->ring[index].req.id, XEN_BLOCK_PROBE_BLK, 0);
+}
+
+static void dispatch_probe_seg(struct task_struct *p, int index)
+{
+ extern void xen_segment_probe(xen_disk_info_t *xdi, int *count);
+ blk_ring_t *blk_ring = p->blk_ring_base;
+ xen_disk_info_t *xdi;
+
+ xdi = phys_to_virt((unsigned long)blk_ring->ring[index].req.buffer);
+ xen_segment_probe(xdi, &num_xdrives);
+
+ make_response(p, blk_ring->ring[index].req.id, XEN_BLOCK_PROBE_SEG, 0);
}
static void dispatch_rw_block_io(struct task_struct *p, int index)
struct buffer_head *bh;
int operation;
unsigned short size;
+ unsigned long block_number = 0L;
+ unsigned long sector_number = 0L;
unsigned long buffer, pfn;
struct pfn_info *page;
+ int xen_device, phys_device = 0;
operation = (blk_ring->ring[index].req.operation == XEN_BLOCK_WRITE) ?
WRITE : READ;
/* set just the important bits of the buffer header */
memset (bh, 0, sizeof (struct buffer_head));
+
+ /* map from virtual xeno devices to physical ide & scsi devices */
+ xen_device = blk_ring->ring[index].req.device;
+ if (IS_XHD_MAJOR(xen_device))
+ {
+ if (xen_device == XHDA_MAJOR) phys_device = MKDEV(IDE0_MAJOR, 0);
+ else if (xen_device == XHDB_MAJOR) phys_device = MKDEV(IDE1_MAJOR, 0);
+ else if (xen_device == XHDC_MAJOR) phys_device = MKDEV(IDE2_MAJOR, 0);
+ else if (xen_device == XHDD_MAJOR) phys_device = MKDEV(IDE3_MAJOR, 0);
+ else
+ {
+ printk (KERN_ALERT "dispatch_rw_block_io: unknown device %d\n",
+ xen_device);
+ BUG();
+ }
+
+ block_number = blk_ring->ring[index].req.block_number;
+ sector_number = blk_ring->ring[index].req.sector_number;
+ }
+ else if (IS_VHD_MAJOR(xen_device))
+ {
+ int s;
+ if (s = xen_segment_map_request(&phys_device, &block_number,
+ §or_number,
+ p, operation, xen_device,
+ blk_ring->ring[index].req.block_number,
+ blk_ring->ring[index].req.sector_number))
+ {
+ printk ("dispatch_rw_block_io: xen_segment_map_request status: %d\n",
+ s);
+ goto bad_descriptor;
+ }
+ }
+ else
+ {
+ printk (KERN_ALERT "dispatch_rw_block_io: unknown device %d\n",
+ xen_device);
+ BUG();
+ }
- bh->b_blocknr = blk_ring->ring[index].req.block_number;
+ bh->b_blocknr = block_number;
bh->b_size = size;
- bh->b_dev = blk_ring->ring[index].req.device;
- bh->b_rsector = blk_ring->ring[index].req.sector_number;
+ bh->b_dev = phys_device;
+ bh->b_rsector = sector_number;
bh->b_data = phys_to_virt(buffer);
bh->b_count.counter = 1;
bh->b_end_io = end_block_io_op;
return;
bad_descriptor:
+ printk (KERN_ALERT "dispatch rw blockio bad descriptor\n");
make_response(p, blk_ring->ring[index].req.id, XEN_BLOCK_READ, 1);
return;
}
static void dump_blockq(u_char key, void *dev_id, struct pt_regs *regs)
{
- printk("Dumping block queue stats: nr_pending = %d\n",
- atomic_read(&nr_pending));
+ struct task_struct *p;
+ blk_ring_t *blk_ring ;
+
+ printk("Dumping block queue stats: nr_pending = %d\n",
+ atomic_read(&nr_pending));
+
+ p = current->next_task;
+ do
+ {
+ printk (KERN_ALERT "Domain: %d\n", p->domain);
+ blk_ring = p->blk_ring_base;
+
+ printk(" req_prod:%d, resp_prod:%d, req_cons:%d\n",
+ blk_ring->req_prod, blk_ring->resp_prod, p->blk_req_cons);
+
+ p = p->next_task;
+ } while (p != current);
}
/* Start-of-day initialisation for a new domain. */
clear_page(p->blk_ring_base);
SHARE_PFN_WITH_DOMAIN(virt_to_page(p->blk_ring_base), p->domain);
p->blkdev_list.next = NULL;
+
+ memset(p->segment_list, 0, sizeof(p->segment_list));
p->segment_count = 0;
+
+ xen_refresh_segment_list(p); /* get any previously created segments */
}
/* End-of-day teardown for a domain. XXX Outstanding requests? */
#include <xeno/slab.h>
#include <xeno/segment.h>
#include <xeno/sched.h>
+#include <xeno/blkdev.h>
#include <xeno/keyhandler.h>
+#include <asm/current.h>
+#include <asm/domain_page.h>
#include <hypervisor-ifs/block.h>
+#include <hypervisor-ifs/xeno-major.h>
int num_xdrives;
drive_t xdrives[XEN_MAX_DISK_COUNT];
segment_t xsegments[XEN_MAX_SEGMENTS];
+/*
+ * xen_segment_map_request
+ *
+ * xen_device must be a valid device.
+ */
+
+int xen_segment_map_request(int *phys_device, /* out */
+ unsigned long *block_number, /* out */
+ unsigned long *sector_number, /* out */
+ struct task_struct *domain,
+ int operation,
+ int xen_device,
+ int xen_block_number,
+ int xen_sector_number)
+{
+ segment_t *seg;
+ int segment_number; /* segment number within this domain */
+ int sum;
+ int loop;
+
+ segment_number = xen_device - XLSEG_MAJOR;
+ seg = domain->segment_list[segment_number];
+
+ if (seg == NULL)
+ {
+ return 1; /* oops. no vhd exists! */
+ }
+
+ /* check domain permissions */
+ if (seg->domain != domain->domain)
+ {
+ return 2; /* domain doesn't own segment */
+ }
+
+ /* check rw access */
+ if ((operation == WRITE && seg->mode != XEN_SEGMENT_RW) ||
+ (operation == READ && seg->mode == XEN_SEGMENT_UNUSED))
+ {
+ return 3; /* access violation */
+ }
+
+ /* find extent, check size */
+ sum = 0;
+ loop = 0;
+ while (loop < seg->num_extents && sum <= xen_block_number)
+ {
+ sum += seg->extents[loop++].size;
+ }
+ sum -= seg->extents[--loop].size; /* rewind */
+
+ if (sum + seg->extents[loop].size <= xen_block_number)
+ {
+ return 4; /* tried to read past the end of the segment */
+ }
+ *block_number = xen_block_number - sum + seg->extents[loop].offset;
+ *sector_number = xen_sector_number - sum + seg->extents[loop].offset;;
+
+ /* get physical device from xdrives */
+ *phys_device = MKDEV(xdrives[seg->extents[loop].disk].major, 0);
+
+ /*
+ printk ("%d %lx %lx %lx %lx : %lx %lx %lx %lx\n",
+ operation,
+ *block_number, xen_block_number, sum, seg->extents[loop].offset,
+ *sector_number, xen_sector_number, sum, seg->extents[loop].offset
+ );
+ */
+
+ return 0;
+}
+
+/*
+ * xen_segment_probe
+ *
+ * return a list of segments to the guestos
+ */
+void xen_segment_probe (xen_disk_info_t *raw_xdi, int *count)
+{
+ int loop, i;
+ xen_disk_info_t *xdi = map_domain_mem(virt_to_phys(raw_xdi));
+
+ for (loop = 0; loop < XEN_MAX_SEGMENTS; loop++ )
+ {
+ if (xsegments[loop].mode != XEN_SEGMENT_UNUSED)
+ {
+ xdi->disks[xdi->count].type = XEN_DISK_VIRTUAL;
+ for (i = 0; i < xsegments[loop].num_extents; i++)
+ {
+ xdi->disks[xdi->count].capacity += xsegments[loop].extents[i].size;
+ }
+ xdi->count++;
+ }
+ }
+
+ unmap_domain_mem(xdi);
+ return;
+}
+
/*
* xen_refresh_segment_list
*
}
if (idx == XEN_MAX_SEGMENTS)
{
- printk (KERN_ALERT "error: xen_segment_create unable to find free slot\n");
+ printk (KERN_ALERT "xen_segment_create: unable to find free slot\n");
+ unmap_domain_mem(xvd);
return 1;
}
xsegments[idx].extents[loop].disk = xvd->extents[loop].disk;
xsegments[idx].extents[loop].offset = xvd->extents[loop].offset;
xsegments[idx].extents[loop].size = xvd->extents[loop].size;
+ if (xsegments[idx].extents[loop].size == 0)
+ {
+ printk (KERN_ALERT "xen_segment_create: extent %d is zero length\n",
+ loop);
+ unmap_domain_mem(xvd);
+ return 1;
+ }
}
+ unmap_domain_mem(xvd);
return 0;
}
static void dump_segments(u_char key, void *dev_id, struct pt_regs *regs)
{
int loop, i;
+ struct task_struct *p;
printk (KERN_ALERT "xdrives\n");
for (loop = 0; loop < num_xdrives; loop++)
printk (KERN_ALERT " %2d: major: 0x%d\n", loop, xdrives[loop].major);
}
- printk (KERN_ALERT "segments\n");
+ printk (KERN_ALERT "segment list\n");
for (loop = 0; loop < XEN_MAX_SEGMENTS; loop++)
{
if (xsegments[loop].mode != XEN_SEGMENT_UNUSED)
}
}
}
+
+ printk (KERN_ALERT "segments by domain\n");
+ p = current->next_task;
+ do
+ {
+ printk (KERN_ALERT " domain: %d\n", p->domain);
+ for (loop = 0; loop < p->segment_count; loop++)
+ {
+ printk (KERN_ALERT " mode:%d domain:%d seg:%d exts:%d\n",
+ p->segment_list[loop]->mode,
+ p->segment_list[loop]->domain,
+ p->segment_list[loop]->segment_number,
+ p->segment_list[loop]->num_extents);
+ }
+ p = p->next_task;
+ } while (p != current);
}
/*
#define XEN_BLOCK_WRITE 1
#define XEN_BLOCK_READA 2 /* currently unused */
#define XEN_BLOCK_SPECIAL 4 /* currently unused */
-#define XEN_BLOCK_PROBE 8 /* determine io configuration from hypervisor */
-#define XEN_BLOCK_DEBUG 16 /* debug */
+#define XEN_BLOCK_PROBE_BLK 8 /* get xhd config from hypervisor */
+#define XEN_BLOCK_DEBUG 16 /* debug */
#define XEN_BLOCK_SEG_CREATE 32 /* create segment (vhd) */
#define XEN_BLOCK_SEG_DELETE 64 /* delete segment (vhd) */
+#define XEN_BLOCK_PROBE_SEG 128 /* get vhd config from hypervisor */
#define BLK_RING_SIZE 128
#define BLK_RING_MAX_ENTRIES (BLK_RING_SIZE - 2)
#define XEN_DISK_IDE 1
#define XEN_DISK_SCSI 2
+#define XEN_DISK_VIRTUAL 3 /* vhd */
typedef struct xen_disk /* physical disk */
{
--- /dev/null
+/*
+ * xeno_major.h
+ *
+ * shared definitions for block IO.
+ */
+
+/*
+ * this belongs in xenolinux/include/linux/major.h except that
+ * xen also needs access...
+ */
+
+
+#ifndef __XENO_MAJOR_H__
+#define __XENO_MAJOR_H__
+
+
+#define XLBLK_MAJOR 123 /* XenoLinux Block Device: xhd */
+#define XHDA_MAJOR 123
+#define XHDB_MAJOR 124
+#define XHDC_MAJOR 125
+#define XHDD_MAJOR 126
+#define XLSEG_MAJOR 234 /* XenoLinux Segment Device: vhd */
+#define VHDA_MAJOR 234
+#define VHDB_MAJOR 235
+#define VHDC_MAJOR 236
+#define VHDD_MAJOR 237
+
+
+/*
+ * XenoLinux Block Device Tests
+ */
+#define IS_XHD_MAJOR(M) ( (M) == XHDA_MAJOR || (M) == XHDB_MAJOR || \
+ (M) == XHDC_MAJOR || (M) == XHDD_MAJOR ? 1 : 0)
+#define IS_VHD_MAJOR(M) ( (M) == VHDA_MAJOR || (M) == VHDB_MAJOR || \
+ (M) == VHDC_MAJOR || (M) == VHDD_MAJOR ? 1 : 0)
+
+#endif
#define UMEM_MAJOR 116 /* http://www.umem.com/ Battery Backed RAM */
+/* note: 123, 124, 125, 126 and 234, 235, 236, 237 are defined in xeno_major */
+#include <hypervisor-ifs/xeno-major.h>
+
#define RTF_MAJOR 150
#define RAW_MAJOR 162
void xen_segment_initialize(void);
void xen_refresh_segment_list (struct task_struct *p);
int xen_segment_create(xv_disk_t *xvd);
+int xen_segment_map_request(int *phys_device, /* out */
+ unsigned long *block_number, /* out */
+ unsigned long *sector_number, /* out */
+ struct task_struct *domain,
+ int operation,
+ int xen_device,
+ int xen_block_number,
+ int xen_sector_number);
#define XEN_MAX_SEGMENTS 100 /* total number of segments across all doms */
} extent_t;
#define XEN_SEGMENT_UNUSED 0 /* bzero default */
-#define XEN_SEGMENT_RO XEN_DISK_READ_WRITE
-#define XEN_SEGMENT_RW XEN_DISK_READ_ONLY
+#define XEN_SEGMENT_RO XEN_DISK_READ_ONLY
+#define XEN_SEGMENT_RW XEN_DISK_READ_WRITE
typedef struct segment
{
O_TARGET := blk.o
-obj-y := xl_block.o xl_segment.o xl_block_test.o
+obj-y := xl_block.o xl_segment.o xl_segment_proc.o xl_block_test.o
include $(TOPDIR)/Rules.make
/******************************************************************************
* xl_block.c
*
- * Xenolinux virtual block-device driver.
+ * Xenolinux virtual block-device driver (xhd).
*
*/
/* Copied from linux/ide.h */
typedef unsigned char byte;
-void xlblk_ide_register_disk(int, unsigned long);
-
#define XLBLK_MAX 32 /* Maximum minor devices we support */
#define XLBLK_MAJOR_NAME "xhd"
#define IDE_PARTN_BITS 6 /* from ide.h::PARTN_BITS */
static blk_ring_t *blk_ring;
static unsigned int resp_cons; /* Response consumer for comms ring. */
-static xen_disk_info_t xen_disk_info;
+static xen_disk_info_t xlblk_disk_info;
atomic_t xlblk_control_count;
-int hypervisor_request(void * id,
- int operation,
- char * buffer,
- unsigned long block_number,
- unsigned short block_size,
- kdev_t device);
+void xlblk_ide_register_disk(int, unsigned long);
+void do_xlseg_requestX (request_queue_t *rq);
+int hypervisor_request(void * id,
+ int operation,
+ char * buffer,
+ unsigned long block_number,
+ unsigned short block_size,
+ kdev_t device,
+ struct gendisk *gd);
/* ------------------------------------------------------------------------
switch (command)
{
- case BLKGETSIZE:
+ case BLKGETSIZE: /* get size */
DPRINTK_IOCTL(" BLKGETSIZE: %x %lx\n", BLKGETSIZE,
- (long) xen_disk_info.disks[0].capacity);
- return put_user(xen_disk_info.disks[0].capacity,
+ (long) xlblk_disk_info.disks[0].capacity);
+ return put_user(xlblk_disk_info.disks[0].capacity,
(unsigned long *) argument);
- case BLKRRPART:
+ case BLKRRPART: /* re-read partition table */
DPRINTK_IOCTL(" BLKRRPART: %x\n", BLKRRPART);
break;
- case BLKSSZGET:
+ case BLKBSZGET: /* get block size */
+ DPRINTK_IOCTL(" BLKBSZGET: %x\n", BLKBSZGET);
+ break;
+
+ case BLKBSZSET: /* set block size */
+ DPRINTK_IOCTL(" BLKBSZSET: %x\n", BLKBSZSET);
+ break;
+
+ case BLKRASET: /* set read-ahead */
+ DPRINTK_IOCTL(" BLKRASET: %x\n", BLKRASET);
+ break;
+
+ case BLKRAGET: /* get read-ahead */
+ DPRINTK_IOCTL(" BLKRAFET: %x\n", BLKRAGET);
+ break;
+
+ case BLKSSZGET: /* get sector size */
DPRINTK_IOCTL(" BLKSSZGET: %x 0x%x\n", BLKSSZGET,
xlblk_hardsect_size[minor_dev]);
return xlblk_hardsect_size[minor_dev];
case HDIO_GETGEO:
+ /* note: these values are complete garbage */
DPRINTK_IOCTL(" HDIO_GETGEO: %x\n", HDIO_GETGEO);
if (!argument) return -EINVAL;
if (put_user(0x00, (unsigned long *) &geo->start)) return -EFAULT;
return 0;
case HDIO_GETGEO_BIG:
+ /* note: these values are complete garbage */
DPRINTK_IOCTL(" HDIO_GETGEO_BIG: %x\n", HDIO_GETGEO_BIG);
if (!argument) return -EINVAL;
if (put_user(0x00, (unsigned long *) &geo->start)) return -EFAULT;
if (put_user(0xff, (byte *)&geo->heads)) return -EFAULT;
if (put_user(0x3f, (byte *)&geo->sectors)) return -EFAULT;
if (put_user(0x106, (unsigned int *) &geo->cylinders)) return -EFAULT;
-
return 0;
default:
* request block io
*
* id: for guest use only.
- * operation: XEN_BLOCK_READ, XEN_BLOCK_WRITE or XEN_BLOCK_PROBE
+ * operation: XEN_BLOCK_{READ,WRITE,PROBE*,SEG*}
* buffer: buffer to read/write into. this should be a
* virtual address in the guest os.
* block_number: block to read
* block_size: size of each block
- * device: ide/hda is 768 or 0x300 should be disk#!!!
+ * device: xhd or vhd
+ * gd: partition information if XEN_BLOCK_{READ,WRITE}
*/
-int hypervisor_request(void * id,
- int operation,
- char * buffer,
- unsigned long block_number,
- unsigned short block_size,
- kdev_t device)
+int hypervisor_request(void * id,
+ int operation,
+ char * buffer,
+ unsigned long block_number,
+ unsigned short block_size,
+ kdev_t device,
+ struct gendisk *gd)
{
int position;
void *buffer_ma;
kdev_t phys_device = (kdev_t) 0;
unsigned long sector_number = 0;
- struct gendisk *gd;
-
+
/*
* Bail if there's no room in the request communication ring. This may be
* because we have a whole bunch of outstanding responses to process. No
{
case XEN_BLOCK_SEG_CREATE:
case XEN_BLOCK_SEG_DELETE:
- case XEN_BLOCK_PROBE:
+ case XEN_BLOCK_PROBE_BLK:
+ case XEN_BLOCK_PROBE_SEG:
phys_device = (kdev_t) 0;
sector_number = 0;
break;
case XEN_BLOCK_READ:
case XEN_BLOCK_WRITE:
- if ( MAJOR(device) != XLBLK_MAJOR )
+ /* only accept requests for xhd and vhd devices */
+ if (!IS_XHD_MAJOR(MAJOR(device)) && !IS_VHD_MAJOR(MAJOR(device)))
panic("error: xl_block::hypervisor_request: "
"unknown device [0x%x]\n", device);
- phys_device = MKDEV(IDE0_MAJOR, 0);
- /* Compute real buffer location on disk */
+ phys_device = MAJOR(device);
+
+ /* Compute real buffer location on disk.
+ * note: gd will be null when we read the partition table.
+ */
sector_number = block_number;
- if ( (gd = (struct gendisk *)xen_disk_info.disks[0].gendisk) != NULL )
- sector_number += gd->part[MINOR(device)&IDE_PARTN_MASK].start_sect;
+ if ( gd != NULL )
+ {
+ sector_number += gd->part[MINOR(device)&IDE_PARTN_MASK].start_sect;
+ }
+
+ /*
+ if (IS_VHD_MAJOR(MAJOR(device)))
+ {
+ printk (KERN_ALERT "%lx + %lx = %lx (%x)\n",
+ block_number,
+ gd->part[MINOR(device)&IDE_PARTN_MASK].start_sect,
+ sector_number, device);
+ }
+ */
break;
default:
{
full = hypervisor_request(
bh, (rw == READ) ? XEN_BLOCK_READ : XEN_BLOCK_WRITE,
- bh->b_data, bh->b_rsector, bh->b_size, bh->b_dev);
-
+ bh->b_data, bh->b_rsector, bh->b_size, bh->b_dev,
+ (struct gendisk *)xlblk_disk_info.disks[0].gendisk);
+
if ( full ) goto out;
queued++;
case XEN_BLOCK_SEG_CREATE :
case XEN_BLOCK_SEG_DELETE :
+ case XEN_BLOCK_PROBE_SEG :
atomic_dec(&xlblk_control_count);
break;
resp_cons = i;
/* KAF: We can push work down at this point. We have the lock. */
- do_xlblk_request(BLK_DEFAULT_QUEUE(MAJOR_NR));
+ /* aho: okay, so this is a bit of a hack. we'll kick every queue... */
+ do_xlblk_request(BLK_DEFAULT_QUEUE(XLBLK_MAJOR));
+ do_xlseg_requestX(BLK_DEFAULT_QUEUE(XLSEG_MAJOR));
spin_unlock_irqrestore(&io_request_lock, flags);
}
goto fail;
}
- memset (&xen_disk_info, 0, sizeof(xen_disk_info));
- xen_disk_info.count = 0;
+ /* probe for disk information */
+ memset (&xlblk_disk_info, 0, sizeof(xlblk_disk_info));
+ xlblk_disk_info.count = 0;
- if ( hypervisor_request(NULL, XEN_BLOCK_PROBE, (char *) &xen_disk_info,
- 0, 0, (kdev_t) 0) )
+ if ( hypervisor_request(NULL, XEN_BLOCK_PROBE_BLK,
+ (char *) &xlblk_disk_info,
+ 0, 0, (kdev_t) 0,
+ (struct gendisk *) NULL))
BUG();
HYPERVISOR_block_io_op();
while ( blk_ring->resp_prod != 1 ) barrier();
- printk (KERN_ALERT "block device probe:\n");
- for ( i = 0; i < xen_disk_info.count; i++ )
+ printk (KERN_ALERT "xhd block device probe:\n");
+ for ( i = 0; i < xlblk_disk_info.count; i++ )
{
printk (KERN_ALERT " %2d: type: %d, capacity: %ld\n",
- i, xen_disk_info.disks[i].type,
- xen_disk_info.disks[i].capacity);
+ i, xlblk_disk_info.disks[i].type,
+ xlblk_disk_info.disks[i].capacity);
}
SET_MODULE_OWNER(&xenolinux_block_fops);
/* initialize global arrays in drivers/block/ll_rw_block.c */
for (i = 0; i < XLBLK_MAX; i++) {
- xlblk_blk_size[i] = xen_disk_info.disks[0].capacity;
+ xlblk_blk_size[i] = xlblk_disk_info.disks[0].capacity;
xlblk_blksize_size[i] = 512;
xlblk_hardsect_size[i] = 512;
xlblk_max_sectors[i] = 128;
*/
blk_queue_headactive(BLK_DEFAULT_QUEUE(xlblk_major), 0);
- xlblk_ide_register_disk(0, xen_disk_info.disks[0].capacity);
+ xlblk_ide_register_disk(0, xlblk_disk_info.disks[0].capacity);
printk(KERN_ALERT
"XenoLinux Virtual Block Device Driver installed [device: %d]\n",
add_gendisk(gd);
- xen_disk_info.disks[idx].gendisk = gd;
+ xlblk_disk_info.disks[idx].gendisk = gd;
- /* default disk size is just a big number. in the future, we
- need a message to probe the devices to determine the actual size */
register_disk(gd, MKDEV(xlblk_major, 0), 1<<IDE_PARTN_BITS,
&xenolinux_block_fops, capacity);
+ {
+ int loop = 0;
+ printk (KERN_ALERT "Partition Table: (capacity: %lx)\n", capacity);
+ for (loop = 0; loop < minors; loop++)
+ {
+ if (gd->part[loop].start_sect && gd->part[loop].nr_sects)
+ {
+ printk (KERN_ALERT
+ " %2d: 0x%6lx %8ld 0x%6lx %7ld\n", loop,
+ gd->part[loop].start_sect, gd->part[loop].start_sect,
+ gd->part[loop].nr_sects, gd->part[loop].nr_sects);
+ }
+ }
+ }
+
return;
}
/* submit request */
hypervisor_request(0, meta.operation, meta.buffer,
meta.block_number, meta.block_size,
- meta.device);
+ meta.device,
+ (struct gendisk *) NULL);
HYPERVISOR_block_io_op();
mdelay(1000); /* should wait for a proper acknowledgement/response. */
-/*
+/******************************************************************************
* xl_segment.c
*
- * XenoLinux virtual disk driver.
+ * Xenolinux virtual block-device driver (vhd).
+ *
*/
-
#include <linux/config.h>
#include <linux/module.h>
-#include <linux/proc_fs.h>
-#include <linux/delay.h>
-#include <asm/uaccess.h>
-#include <asm/atomic.h>
+#include <linux/kernel.h>
+#include <linux/sched.h>
+#include <linux/slab.h>
+#include <linux/string.h>
+#include <linux/errno.h>
+
+#include <linux/fs.h>
+#include <linux/hdreg.h>
+#include <linux/blkdev.h>
+#include <linux/major.h>
#include <asm/hypervisor-ifs/block.h>
#include <asm/hypervisor-ifs/hypervisor-if.h>
+#include <asm/io.h>
+#include <asm/atomic.h>
+#include <asm/uaccess.h>
+
+#define MAJOR_NR XLSEG_MAJOR /* force defns in blk.h, must precede include */
+static int xlseg_major = XLSEG_MAJOR;
+#include <linux/blk.h>
+
+/* Copied from linux/ide.h */
+typedef unsigned char byte;
-static struct proc_dir_entry *vhd;
-xv_disk_t xvd;
+#define XLSEG_MAX 32 /* Maximum minor devices we support */
+#define XLSEG_MAJOR_NAME "xhd"
+
+static int xlseg_blk_size[XLSEG_MAX];
+static int xlseg_blksize_size[XLSEG_MAX];
+static int xlseg_read_ahead;
+static int xlseg_hardsect_size[XLSEG_MAX];
+static int xlseg_max_sectors[XLSEG_MAX];
extern atomic_t xlblk_control_count; /* xl_block.c */
-/******************************************************************/
+int hypervisor_request(void * id,
+ int operation,
+ char * buffer,
+ unsigned long block_number,
+ unsigned short block_size,
+ kdev_t device,
+ struct gendisk *gd);
+void xlseg_register_disk(int idx, unsigned long capacity);
+
+#if 0
+#define DPRINTK(_f, _a...) printk ( KERN_ALERT _f , ## _a )
+#define DPRINTK_IOCTL(_f, _a...) printk ( KERN_ALERT _f , ## _a )
+#else
+#define DPRINTK(_f, _a...) ((void)0)
+#define DPRINTK_IOCTL(_f, _a...) ((void)0)
+#endif
+
+static xen_disk_info_t xlseg_disk_info;
-static int proc_read_vhd(char *page, char **start, off_t off,
- int count, int *eof, void *data)
+/* ------------------------------------------------------------------------
+ */
+
+static int xenolinux_segment_open(struct inode *inode, struct file *filep)
{
- return 0;
+ DPRINTK("xenolinux_segment_release\n");
+ return 0;
}
-#define isdelim(c) \
- (c==' '||c==','||c=='\n'||c=='\r'||c=='\t'||c==':'||c=='('||c==')' ? 1 : 0)
+static int xenolinux_segment_release(struct inode *inode, struct file *filep)
+{
+ DPRINTK("xenolinux_segment_release\n");
+ return 0;
+}
-char *get_string(char *string) /* a bit like strtok */
+static int xenolinux_segment_ioctl(struct inode *inode, struct file *filep,
+ unsigned command, unsigned long argument)
{
- static char *temp;
- int loop = 0;
+ int minor_dev;
+ struct hd_geometry *geo = (struct hd_geometry *)argument;
+ struct gendisk *gd = (struct gendisk *)xlseg_disk_info.disks[0].gendisk;
+
+ DPRINTK("xenolinux_segment_ioctl\n");
+
+ /* check permissions */
+ if (!capable(CAP_SYS_ADMIN)) return -EPERM;
+ if (!inode) return -EINVAL;
+ minor_dev = MINOR(inode->i_rdev);
+ if (minor_dev >= XLSEG_MAX) return -ENODEV;
+
+ DPRINTK_IOCTL("command: 0x%x, argument: 0x%lx, minor: 0x%x\n",
+ command, (long) argument, minor_dev);
+
+ switch (command)
+ {
+ case BLKGETSIZE:
+ if (gd != NULL)
+ {
+ printk(KERN_ALERT "minordev: %d\n", minor_dev);
+ printk(KERN_ALERT "[0] start: %lx\n", gd->part[0].start_sect);
+ printk(KERN_ALERT "[0] count: %lx\n", gd->part[0].nr_sects);
+ printk(KERN_ALERT "[1] start: %lx\n", gd->part[1].start_sect);
+ printk(KERN_ALERT "[1] count: %lx\n", gd->part[1].nr_sects);
+ printk(KERN_ALERT "[2] start: %lx\n", gd->part[2].start_sect);
+ printk(KERN_ALERT "[2] count: %lx\n", gd->part[2].nr_sects);
+
+ DPRINTK_IOCTL(" BLKGETSIZE gd: %x %lx\n", BLKGETSIZE,
+ gd->part[minor_dev].nr_sects);
+ return put_user(gd->part[minor_dev].nr_sects,
+ (unsigned long *)argument);
+ }
+ else
+ {
+ DPRINTK_IOCTL(" BLKGETSIZE disk: %x %lx\n", BLKGETSIZE,
+ xlseg_disk_info.disks[0].capacity);
+ return put_user(xlseg_disk_info.disks[0].capacity,
+ (unsigned long *) argument);
+ }
+
+ case BLKRRPART:
+ DPRINTK_IOCTL(" BLKRRPART: \n");
+ /* we don't have re-validate drive yet... so you need to reboot! */
+ break;
+
+ case BLKSSZGET:
+ DPRINTK_IOCTL(" BLKSSZGET: %d\n",
+ xlseg_hardsect_size[minor_dev]);
+ return xlseg_hardsect_size[minor_dev];
+
+ case HDIO_GETGEO:
+ /* note: these values are complete garbage */
+ DPRINTK_IOCTL(" HDIO_GETGEO: \n");
+ if (!argument) return -EINVAL;
+ if (put_user(0x00, (unsigned long *) &geo->start)) return -EFAULT;
+ if (put_user(0xff, (byte *)&geo->heads)) return -EFAULT;
+ if (put_user(0x3f, (byte *)&geo->sectors)) return -EFAULT;
+ if (put_user(0x106, (unsigned short *)&geo->cylinders)) return -EFAULT;
+ return 0;
+
+ case HDIO_GETGEO_BIG:
+ /* note: these values are complete garbage */
+ DPRINTK_IOCTL(" HDIO_GETGEO_BIG\n");
+ if (!argument) return -EINVAL;
+ if (put_user(0x00, (unsigned long *) &geo->start)) return -EFAULT;
+ if (put_user(0xff, (byte *)&geo->heads)) return -EFAULT;
+ if (put_user(0x3f, (byte *)&geo->sectors)) return -EFAULT;
+ if (put_user(0x106, (unsigned int *) &geo->cylinders)) return -EFAULT;
+ return 0;
+
+ default:
+ DPRINTK_IOCTL(" eh? unknown ioctl\n");
+ break;
+ }
+
+ return 0;
+}
- if (string != NULL)
- temp = string;
- else
- string = temp;
+static int xenolinux_segment_check(kdev_t dev)
+{
+ DPRINTK("xenolinux_segment_check\n");
+ return 0;
+}
- try_again:
+static int xenolinux_segment_revalidate(kdev_t dev)
+{
+ DPRINTK("xenolinux_segment_revalidate\n");
+ return 0;
+}
- while (!isdelim(string[loop]))
- {
- if (string[loop] == '\0')
- return NULL;
- loop++;
- }
+void do_xlseg_requestX (request_queue_t *rq)
+{
+ /* this is a bit dumb. do_xlseg_request is defined in blk.h
+ and this is thus static. but we have cooperative
+ device drivers... */
+ do_xlseg_request(rq);
+}
- string[loop] = '\0';
- temp = (string + loop + 1);
+/*
+ * do_xlseg_request
+ * read a block; request is in a request queue
+ */
+static void do_xlseg_request (request_queue_t *rq)
+{
+ struct request *req;
+ struct buffer_head *bh;
+ int rw, nsect, full, queued = 0;
+
+ /* DPRINTK("do_xlseg_request for '%s'\n", DEVICE_NAME); */
- if (loop == 0)
- {
- string = temp;
- goto try_again;
- }
+ while ( !rq->plugged && !QUEUE_EMPTY )
+ {
+ if ( (req = CURRENT) == NULL ) goto out;
+
+ DPRINTK("do_xlseg_request %p: cmd %i, sec %lx, (%li/%li) bh:%p\n",
+ req, req->cmd, req->sector,
+ req->current_nr_sectors, req->nr_sectors, req->bh);
+
+ rw = req->cmd;
+ if ( rw == READA ) rw = READ;
+ if ((rw != READ) && (rw != WRITE))
+ panic("XenoLinux Virtual Segment Device: bad cmd: %d\n", rw);
+
+ req->errors = 0;
+
+ bh = req->bh;
+ while ( bh != NULL )
+ {
+ full = hypervisor_request(
+ bh, (rw == READ) ? XEN_BLOCK_READ : XEN_BLOCK_WRITE,
+ bh->b_data, bh->b_rsector, bh->b_size, bh->b_dev,
+ (struct gendisk *)xlseg_disk_info.disks[0].gendisk);
+
+ if ( full )
+ {
+ goto out;
+ }
+
+ queued++;
+
+ /* Dequeue the buffer head from the request. */
+ nsect = bh->b_size >> 9;
+ req->bh = bh->b_reqnext;
+ bh->b_reqnext = NULL;
+ bh = req->bh;
+
+ if ( bh != NULL )
+ {
+ /* There's another buffer head to do. Update the request. */
+ req->hard_sector += nsect;
+ req->hard_nr_sectors -= nsect;
+ req->sector = req->hard_sector;
+ req->nr_sectors = req->hard_nr_sectors;
+ req->current_nr_sectors = bh->b_size >> 9;
+ req->buffer = bh->b_data;
+ }
+ else
+ {
+ /* That was the last buffer head. Finalise the request. */
+ if ( end_that_request_first(req, 1, "XenSeg") ) BUG();
+ blkdev_dequeue_request(req);
+ end_that_request_last(req);
+ }
+ }
+ }
- return string;
+ out:
+ if ( queued != 0 ) HYPERVISOR_block_io_op();
}
-#define isdigit(c) (c >= '0' && c <= '9' ? 1 : 0)
-unsigned long to_number(char *string) /* atoi */
+static struct block_device_operations xenolinux_segment_fops =
{
- unsigned long value = 0;
+ open: xenolinux_segment_open,
+ release: xenolinux_segment_release,
+ ioctl: xenolinux_segment_ioctl,
+ check_media_change: xenolinux_segment_check,
+ revalidate: xenolinux_segment_revalidate,
+};
- if (string == NULL) return 0;
- while (!isdigit(*string) && *string != '\0') string++;
+int __init xlseg_init(void)
+{
+ int i, result;
+ int counter;
- while (isdigit(*string))
- {
- value = value * 10 + (*string - '0');
- string++;
- }
+ /* probe for disk information */
+ memset (&xlseg_disk_info, 0, sizeof(xlseg_disk_info));
+ xlseg_disk_info.count = 0;
- return value;
-}
-static int proc_write_vhd(struct file *file, const char *buffer,
- unsigned long count, void *data)
-{
- char *local = kmalloc((count + 1) * sizeof(char), GFP_KERNEL);
- char *string;
- int loop;
- int counter;
- xv_disk_t xvd;
-
- memset (&xvd, 0, sizeof(xvd));
-
- if (copy_from_user(local, buffer, count))
- {
- return -EFAULT;
- }
- local[count] = '\0';
-
- string = get_string(local); /* look for Domain */
- if (string == NULL) /* empty string */
- {
- return count;
- }
- if (*string != 'd' && *string != 'D')
- {
- printk (KERN_ALERT
- "error: domain specifier missing [%s]. should be \"domain\".\n",
- string);
- return count;
- }
-
- string = get_string(NULL); /* domain number */
- if (string == NULL)
- {
- printk (KERN_ALERT "error: domain number missing\n");
- return count;
- }
- xvd.domain = (int) to_number(string);
-
- string = get_string(NULL);
- if (string && (strcmp(string, "RO") == 0 || strcmp(string, "ro") == 0))
- {
- xvd.mode = XEN_DISK_READ_ONLY;
- }
- else if (string && (strcmp(string, "RW") == 0 || strcmp(string, "rw") == 0))
- {
- xvd.mode = XEN_DISK_READ_ONLY;
- }
- else
- {
- printk (KERN_ALERT
- "error: bad mode [%s]. should be \"rw\" or \"ro\".\n",
- string);
- return count;
- }
-
- string = get_string(NULL); /* look for Segment */
- if (string == NULL || (*string != 's' && *string != 'S'))
- {
- printk (KERN_ALERT
- "error: segment specifier missing [%s]. should be \"segment\".\n",
- string);
- return count;
- }
-
- string = get_string(NULL); /* segment number */
- if (string == NULL)
- {
- printk (KERN_ALERT "error: segment number missing\n");
- return count;
- }
- xvd.segment = (int) to_number(string);
-
- string = get_string(NULL); /* look for Extents */
- if (string == NULL || (*string != 'e' && *string != 'E'))
- {
- printk (KERN_ALERT
- "error: extents specifier missing [%s]. should be \"extents\".\n",
- string);
- return count;
- }
-
- string = get_string(NULL); /* number of extents */
- if (string == NULL)
- {
- printk (KERN_ALERT "error: number of extents missing\n");
- return count;
- }
- xvd.ext_count = (int) to_number(string);
-
- /* ignore parenthesis */
-
- for (loop = 0; loop < xvd.ext_count; loop++)
- {
- string = get_string(NULL); /* look for Disk */
- if (string == NULL || (*string != 'd' && *string != 'D'))
{
- printk (KERN_ALERT
- "hmm, extent disk specifier missing [%s]. should be \"disk\".\n",
- string);
- return count;
+ /* get lock xlblk_control_lock */
+ counter = atomic_read(&xlblk_control_count);
+ atomic_inc(&xlblk_control_count);
+ /* release lock xlblk_control_lock */
}
- string = get_string(NULL); /* disk number */
- if (string == NULL)
- {
- printk (KERN_ALERT "error: disk number missing\n");
- return count;
+ if ( hypervisor_request(NULL, XEN_BLOCK_PROBE_SEG,
+ (char *) &xlseg_disk_info,
+ 0, 0, (kdev_t) 0,
+ (struct gendisk *)NULL) )
+ BUG();
+ HYPERVISOR_block_io_op();
+ while (atomic_read(&xlblk_control_count) != counter) barrier();
+
+ printk (KERN_ALERT "vhd block device probe:\n");
+ for ( i = 0; i < xlseg_disk_info.count; i++ )
+ {
+ printk (KERN_ALERT " %2d: type: %d, capacity: %ld\n",
+ i, xlseg_disk_info.disks[i].type,
+ xlseg_disk_info.disks[i].capacity);
}
- xvd.extents[loop].disk = (int) to_number(string);
- string = get_string(NULL); /* look for Offset */
- if (string == NULL || (*string != 'o' && *string != 'O'))
- {
- printk (KERN_ALERT
- "error: disk offset missing [%s]. should be \"offset\".\n",
- string);
- return count;
+ SET_MODULE_OWNER(&xenolinux_segment_fops);
+ result = register_blkdev(xlseg_major, "segment", &xenolinux_segment_fops);
+ if (result < 0) {
+ printk (KERN_ALERT "xenolinux segment: can't get major %d\n",
+ xlseg_major);
+ return result;
}
- string = get_string(NULL); /* offset */
- if (string == NULL)
- {
- printk (KERN_ALERT "error: offset missing\n");
- return count;
- }
- xvd.extents[loop].offset = to_number(string);
- string = get_string(NULL); /* look for Size */
- if (string == NULL || (*string != 's' && *string != 'S'))
- {
- printk (KERN_ALERT
- "error: extent size missing [%s]. should be \"size\".\n",
- string);
- return count;
- }
- string = get_string(NULL); /* size */
- if (string == NULL)
+ /* initialize global arrays in drivers/block/ll_rw_block.c */
+ for (i = 0; i < XLSEG_MAX; i++)
{
- printk (KERN_ALERT "error: extent size missing\n");
- return count;
+ xlseg_blk_size[i] = xlseg_disk_info.disks[0].capacity ;
+ xlseg_blksize_size[i] = 512;
+ xlseg_hardsect_size[i] = 512;
+ xlseg_max_sectors[i] = 128;
}
- xvd.extents[loop].size = to_number(string);
- }
+ xlseg_read_ahead = 8;
- {
- /* get lock xlblk_control_lock */
- counter = atomic_read(&xlblk_control_count);
- atomic_inc(&xlblk_control_count);
- /* release lock xlblk_control_lock */
- }
+ blk_size[xlseg_major] = xlseg_blk_size;
+ blksize_size[xlseg_major] = xlseg_blksize_size;
+ hardsect_size[xlseg_major] = xlseg_hardsect_size;
+ read_ahead[xlseg_major] = xlseg_read_ahead;
+ max_sectors[xlseg_major] = xlseg_max_sectors;
- hypervisor_request (NULL, XEN_BLOCK_SEG_CREATE, (char *)&xvd,
- 0, 0, (kdev_t) 0);
- HYPERVISOR_block_io_op();
+ blk_init_queue(BLK_DEFAULT_QUEUE(xlseg_major), do_xlseg_request);
- while (atomic_read(&xlblk_control_count) != counter) barrier();
+ /*
+ * Turn off barking 'headactive' mode. We dequeue buffer heads as
+ * soon as we pass them down to Xen.
+ */
+ blk_queue_headactive(BLK_DEFAULT_QUEUE(xlseg_major), 0);
- /* while ( blk_ring->resp_prod != 1 ) barrier(); */
+ xlseg_register_disk(0, xlseg_disk_info.disks[0].capacity);
- /* mdelay(1000); */
-
- return count;
+ printk(KERN_ALERT
+ "XenoLinux Virtual Segment Device Driver installed [device: %d]\n",
+ xlseg_major);
+ return 0;
}
-/******************************************************************/
-
-int __init xlseg_init(void)
+void xlseg_register_disk(int idx, unsigned long capacity)
{
- vhd = create_proc_entry("xeno/dom0/vhd", 0644, NULL);
- if (vhd == NULL)
- {
- panic ("xlseg_init: unable to create vhd proc entry\n");
- }
- vhd->data = NULL;
- vhd->read_proc = proc_read_vhd;
- vhd->write_proc = proc_write_vhd;
- vhd->owner = THIS_MODULE;
-
- memset(&xvd, 0, sizeof(xvd));
-
- printk(KERN_ALERT "XenoLinux Virtual Disk Device Driver installed\n");
- return 0;
+ int units;
+ int minors;
+ struct gendisk *gd;
+
+ /* plagarized from ide-probe.c::init_gendisk */
+
+ units = 2; /* from ide.h::MAX_DRIVES */
+
+#define IDE_PARTN_BITS 6 /* from ide.h::PARTN_BITS */
+
+ minors = units * (1<<IDE_PARTN_BITS);
+ gd = kmalloc (sizeof(struct gendisk), GFP_KERNEL);
+ gd->sizes = kmalloc (minors * sizeof(int), GFP_KERNEL);
+ gd->part = kmalloc (minors * sizeof(struct hd_struct), GFP_KERNEL);
+ memset(gd->part, 0, minors * sizeof(struct hd_struct));
+
+ gd->major = xlseg_major;
+ gd->major_name = XLSEG_MAJOR_NAME;
+ gd->minor_shift = IDE_PARTN_BITS;
+ gd->max_p = 1<<IDE_PARTN_BITS;
+ gd->nr_real = units;
+ gd->real_devices = NULL;
+ gd->next = NULL;
+ gd->fops = &xenolinux_segment_fops;
+ gd->de_arr = kmalloc (sizeof *gd->de_arr * units, GFP_KERNEL);
+ gd->flags = kmalloc (sizeof *gd->flags * units, GFP_KERNEL);
+
+ if (gd->de_arr)
+ memset (gd->de_arr, 0, sizeof *gd->de_arr * units);
+
+ if (gd->flags)
+ memset (gd->flags, 0, sizeof *gd->flags * units);
+
+ add_gendisk(gd);
+
+ xlseg_disk_info.disks[idx].gendisk = gd;
+
+ register_disk(gd, MKDEV(xlseg_major, 0), 1<<IDE_PARTN_BITS,
+ &xenolinux_segment_fops, capacity);
+
+ {
+ int loop = 0;
+ printk (KERN_ALERT "Partition Table: (capacity: %lx)\n", capacity);
+ for (loop = 0; loop < minors; loop++)
+ {
+ if (gd->part[loop].start_sect && gd->part[loop].nr_sects)
+ {
+ printk (KERN_ALERT
+ " %2d: 0x%6lx %8ld 0x%6lx %7ld\n", loop,
+ gd->part[loop].start_sect, gd->part[loop].start_sect,
+ gd->part[loop].nr_sects, gd->part[loop].nr_sects);
+ }
+ }
+ }
+
+ return;
}
+
static void __exit xlseg_cleanup(void)
{
- printk(KERN_ALERT "XenoLinux Virtual Disk Device Driver uninstalled\n");
+ /* CHANGE FOR MULTIQUEUE */
+ blk_cleanup_queue(BLK_DEFAULT_QUEUE(xlseg_major));
+
+ /* clean up global arrays */
+ read_ahead[xlseg_major] = 0;
+
+ if (blk_size[xlseg_major])
+ kfree(blk_size[xlseg_major]);
+ blk_size[xlseg_major] = NULL;
+
+ if (blksize_size[xlseg_major])
+ kfree(blksize_size[xlseg_major]);
+ blksize_size[xlseg_major] = NULL;
+
+ if (hardsect_size[xlseg_major])
+ kfree(hardsect_size[xlseg_major]);
+ hardsect_size[xlseg_major] = NULL;
+
+ /* XXX: free each gendisk */
+ if (unregister_blkdev(xlseg_major, "block"))
+ printk(KERN_ALERT
+ "XenoLinux Virtual Segment Device Driver uninstalled w/ errs\n");
+ else
+ printk(KERN_ALERT
+ "XenoLinux Virtual Segment Device Driver uninstalled\n");
+
+ return;
}
+
#ifdef MODULE
module_init(xlseg_init);
module_exit(xlseg_cleanup);
--- /dev/null
+/*
+ * xl_segment_proc.c
+ *
+ * XenoLinux virtual disk proc interface .
+ */
+
+
+#include <linux/config.h>
+#include <linux/module.h>
+
+#include <linux/proc_fs.h>
+#include <linux/delay.h>
+#include <asm/uaccess.h>
+#include <asm/atomic.h>
+
+#include <asm/hypervisor-ifs/block.h>
+#include <asm/hypervisor-ifs/hypervisor-if.h>
+
+static struct proc_dir_entry *vhd;
+xv_disk_t xvd;
+
+extern atomic_t xlblk_control_count; /* xl_block.c */
+
+int hypervisor_request(void * id,
+ int operation,
+ char * buffer,
+ unsigned long block_number,
+ unsigned short block_size,
+ kdev_t device,
+ struct gendisk *gd);
+
+/******************************************************************/
+
+static int proc_read_vhd(char *page, char **start, off_t off,
+ int count, int *eof, void *data)
+{
+ return 0;
+}
+
+#define isdelim(c) \
+ (c==' '||c==','||c=='\n'||c=='\r'||c=='\t'||c==':'||c=='('||c==')' ? 1 : 0)
+
+char *get_string(char *string) /* a bit like strtok */
+{
+ static char *temp;
+ int loop = 0;
+
+ if (string != NULL)
+ temp = string;
+ else
+ string = temp;
+
+ try_again:
+
+ while (!isdelim(string[loop]))
+ {
+ if (string[loop] == '\0')
+ return NULL;
+ loop++;
+ }
+
+ string[loop] = '\0';
+ temp = (string + loop + 1);
+
+ if (loop == 0)
+ {
+ string = temp;
+ goto try_again;
+ }
+
+ return string;
+}
+
+
+#define isdigit(c) (c >= '0' && c <= '9' ? 1 : 0)
+unsigned long to_number(char *string) /* atoi */
+{
+ unsigned long value = 0;
+
+ if (string == NULL) return 0;
+
+ while (!isdigit(*string) && *string != '\0') string++;
+
+ while (isdigit(*string))
+ {
+ value = value * 10 + (*string - '0');
+ string++;
+ }
+
+ return value;
+}
+
+static int proc_write_vhd(struct file *file, const char *buffer,
+ unsigned long count, void *data)
+{
+ char *local = kmalloc((count + 1) * sizeof(char), GFP_KERNEL);
+ char *string;
+ int loop;
+ int counter;
+ xv_disk_t xvd;
+
+ memset (&xvd, 0, sizeof(xvd));
+
+ if (copy_from_user(local, buffer, count))
+ {
+ return -EFAULT;
+ }
+ local[count] = '\0';
+
+ string = get_string(local); /* look for Domain */
+ if (string == NULL) /* empty string */
+ {
+ return count;
+ }
+ if (*string != 'd' && *string != 'D')
+ {
+ printk (KERN_ALERT
+ "error: domain specifier missing [%s]. should be \"domain\".\n",
+ string);
+ return count;
+ }
+
+ string = get_string(NULL); /* domain number */
+ if (string == NULL)
+ {
+ printk (KERN_ALERT "error: domain number missing\n");
+ return count;
+ }
+ xvd.domain = (int) to_number(string);
+
+ string = get_string(NULL);
+ if (string && (strcmp(string, "RO") == 0 || strcmp(string, "ro") == 0))
+ {
+ xvd.mode = XEN_DISK_READ_ONLY;
+ }
+ else if (string && (strcmp(string, "RW") == 0 || strcmp(string, "rw") == 0))
+ {
+ xvd.mode = XEN_DISK_READ_WRITE;
+ }
+ else
+ {
+ printk (KERN_ALERT
+ "error: bad mode [%s]. should be \"rw\" or \"ro\".\n",
+ string);
+ return count;
+ }
+
+ string = get_string(NULL); /* look for Segment */
+ if (string == NULL || (*string != 's' && *string != 'S'))
+ {
+ printk (KERN_ALERT
+ "error: segment specifier missing [%s]. should be \"segment\".\n",
+ string);
+ return count;
+ }
+
+ string = get_string(NULL); /* segment number */
+ if (string == NULL)
+ {
+ printk (KERN_ALERT "error: segment number missing\n");
+ return count;
+ }
+ xvd.segment = (int) to_number(string);
+
+ string = get_string(NULL); /* look for Extents */
+ if (string == NULL || (*string != 'e' && *string != 'E'))
+ {
+ printk (KERN_ALERT
+ "error: extents specifier missing [%s]. should be \"extents\".\n",
+ string);
+ return count;
+ }
+
+ string = get_string(NULL); /* number of extents */
+ if (string == NULL)
+ {
+ printk (KERN_ALERT "error: number of extents missing\n");
+ return count;
+ }
+ xvd.ext_count = (int) to_number(string);
+
+ /* ignore parenthesis */
+
+ for (loop = 0; loop < xvd.ext_count; loop++)
+ {
+ string = get_string(NULL); /* look for Disk */
+ if (string == NULL || (*string != 'd' && *string != 'D'))
+ {
+ printk (KERN_ALERT
+ "hmm, extent disk specifier missing [%s]. should be \"disk\".\n",
+ string);
+ return count;
+ }
+ string = get_string(NULL); /* disk number */
+ if (string == NULL)
+ {
+ printk (KERN_ALERT "error: disk number missing\n");
+ return count;
+ }
+ xvd.extents[loop].disk = (int) to_number(string);
+
+ string = get_string(NULL); /* look for Offset */
+ if (string == NULL || (*string != 'o' && *string != 'O'))
+ {
+ printk (KERN_ALERT
+ "error: disk offset missing [%s]. should be \"offset\".\n",
+ string);
+ return count;
+ }
+ string = get_string(NULL); /* offset */
+ if (string == NULL)
+ {
+ printk (KERN_ALERT "error: offset missing\n");
+ return count;
+ }
+ xvd.extents[loop].offset = to_number(string);
+
+ string = get_string(NULL); /* look for Size */
+ if (string == NULL || (*string != 's' && *string != 'S'))
+ {
+ printk (KERN_ALERT
+ "error: extent size missing [%s]. should be \"size\".\n",
+ string);
+ return count;
+ }
+ string = get_string(NULL); /* size */
+ if (string == NULL)
+ {
+ printk (KERN_ALERT "error: extent size missing\n");
+ return count;
+ }
+ xvd.extents[loop].size = to_number(string);
+ }
+
+ {
+ /* get lock xlblk_control_lock */
+ counter = atomic_read(&xlblk_control_count);
+ atomic_inc(&xlblk_control_count);
+ /* release lock xlblk_control_lock */
+ }
+ if (hypervisor_request (NULL, XEN_BLOCK_SEG_CREATE, (char *)&xvd,
+ 0, 0, (kdev_t) 0,
+ (struct gendisk *)NULL))
+ BUG();
+ HYPERVISOR_block_io_op();
+
+ while (atomic_read(&xlblk_control_count) != counter) barrier();
+
+ return count;
+}
+
+/******************************************************************/
+
+int __init xlseg_proc_init(void)
+{
+ vhd = create_proc_entry("xeno/dom0/vhd", 0644, NULL);
+ if (vhd == NULL)
+ {
+ panic ("xlseg_init: unable to create vhd proc entry\n");
+ }
+ vhd->data = NULL;
+ vhd->read_proc = proc_read_vhd;
+ vhd->write_proc = proc_write_vhd;
+ vhd->owner = THIS_MODULE;
+
+ memset(&xvd, 0, sizeof(xvd));
+
+ printk(KERN_ALERT "XenoLinux Virtual Disk Device Monitor installed\n");
+ return 0;
+}
+
+static void __exit xlseg_proc_cleanup(void)
+{
+ printk(KERN_ALERT "XenoLinux Virtual Disk Device Monitor uninstalled\n");
+}
+
+#ifdef MODULE
+module_init(xlseg_proc_init);
+module_exit(xlseg_proc_cleanup);
+#endif
#ifdef CONFIG_XENOLINUX_BLOCK
xlblk_init();
xlseg_init();
+ xlseg_proc_init();
#endif
return 0;
/* #define DEVICE_INTR */
#define DEVICE_NR(device) (MINOR(device))
+#elif (MAJOR_NR == XLSEG_MAJOR)
+
+#define DEVICE_NAME "xeno segment"
+#define DEVICE_REQUEST do_xlseg_request
+/* #define DEVICE_INTR */
+#define DEVICE_NR(device) (MINOR(device))
+
#endif /* MAJOR_NR == whatever */
/* provide DEVICE_xxx defaults, if not explicitly defined
#define UMEM_MAJOR 116 /* http://www.umem.com/ Battery Backed RAM */
-#define XLBLK_MAJOR 123 /* XenoLinux Block Device */
+/* note: 123, 124, 125, 126 and 234, 235, 236, 237 are defined in xeno_major */
+#include <asm/hypervisor-ifs/xeno-major.h>
#define RTF_MAJOR 150
#define RAW_MAJOR 162
{ "xhdb", 0x7C00 },
{ "xhdc", 0x7D00 },
{ "xhdd", 0x7E00 },
+ { "vhda", 0xEA00 },
+ { "vhdb", 0xEB00 },
+ { "vhdc", 0xEC00 },
+ { "vhdd", 0xED00 },
#endif
{ "nftla", 0x5d00 },
{ "nftlb", 0x5d10 },